package com.cy.pj.sys.Service;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.util.Arrays;

/**
 * 通过切面学习Spring AOP中各种通知方法的应用
 */
@Order(2) //注解@Order优先执行,数字越小，越先执行
@Aspect
@Component
public class SysTimeAspect通知方法执行顺序先进后出 {
    @Pointcut("@annotation(com.cy.pj.sys.commom.annotation自定义注解类.RequiredTime)")
    public void doTime() {}

    /**@Before描述的方法在目标业务执行之前执行
     * 通常会在@Before方法中做一些目标方法参数数据的过滤或预处理
     * 所有非@Around通知方法中都可以使用JointPoint作为连接点参数
     * */
@Before("doTime()")
    public void doBefore(JoinPoint joinPoint){
    Object[] args=joinPoint.getArgs();
    System.out.println(Arrays.toString(args));
    //在这里拿到参数后，可以对参数进行校验，校验不合格抛出异常
    System.out.println("@Before");
    }

    /**.@After描述的方法在目标业务执行之后执行(无论目标方法是否出现异常)
     * 通常会在@After描述的方法中进行一些资源释放操作
     * */
@After("doTime()")
public void doAfter(){
    System.out.println("@After");
}

    /**
     *@AfterReturning注解描述的方法，在目标方法正常结束时执行
     * 可以在这样的方法进行缓存更新操作(清除，更新)
     */
    @AfterReturning("doTime()")
public void doAfterReturning(){
    System.out.println("@AfterReturning");
}

    /**
     * @AfterThrowing注解描述的方法，在目标方法异常结束时执行
     * 例如，可以在此方法中，可以进行错误日志的记录，可以报警，发送邮件，发送短信
     */
    @AfterThrowing("doTime()")
public void doAfterThrowing(){
    System.out.println("@AfterThrowing");
    }

    /** @Around的优先级是最高的
     * @Around 描述的方法可以在内部通过连接点对象，手动调用目标方法proceed()
     * @param joinPoint 连接点对象。@Around描述的方法可以通过ProceedingJoinPoint连接点对象
     *                  调用目标方法。
     * @throws Throwable
     * @return
     */
    @Around("doTime()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("SysTimeAspect.before");
try{
    /**proceed方法执行逻辑->1,先执行本类其它before，其它切面的before，2,目标方法，3(@Around之外的)当前或其它切面的后续通知方法
     * 4,先进后出，@Around其它的@After执行完后，在执行@Around的内容
    */
Object result=joinPoint.proceed();
    System.out.println("@Around.AfterReturning");
  return result;
}catch(Throwable e){
    e.printStackTrace();
    System.out.println("@Around.AfterThrowing");
    throw e;

}finally{
    System.out.println("@Around.After");
}
    }
}
